#ifndef FITNESS_PERMUTACION_CU
#define FITNESS_PERMUTACION_CU

#include<math.h>
#include "fitnessPermutacion.cuh"
#include "../utils/global.cuh"

float calcularFitnessPermutacionCPU(int* poblacion, int posicion, float* matrizCostosHost){
	float fitness = 0;
	for(int i = 0; i < cantGenesEnCromosoma; i++){
	  fitness = fitness + matrizCostosHost[poblacion[posicion + i] * cantGenesEnCromosoma + poblacion[posicion + ((i + 1) % cantGenesEnCromosoma)]];
	}
	return -fitness;
}

//posicion es la posicion del primer gen del individuo
__device__ float calcularFitnessPermutacionGPU(int* poblacion, int posicion, float* matrizCostosDevice){
	float fitness = 0;
	for(int i = 0; i < cantGenesEnCromosomaDevice*cantCromosomasPoblacionDevice; i=i+cantCromosomasPoblacionDevice){
		fitness = fitness + matrizCostosDevice[poblacion[posicion + i] * cantGenesEnCromosomaDevice + poblacion[posicion + ((i + cantCromosomasPoblacionDevice) % (cantGenesEnCromosomaDevice*cantCromosomasPoblacionDevice))]];
	}
	return -fitness;
}

char ** split ( char *string, const char sep) {
	char **lista;
	char *p = string;
	int i = 0;

	int pos = 0;
	const int len = strlen (string);

	lista = (char **) malloc (sizeof (char *));
	if (lista == NULL) { // No se pudo alocar la memoria
		return NULL;
	}

	lista[pos] = NULL;

	while (i < len){

		while ((p[i] == sep) && (i < len)){
			i++;
		}
		
		if (i < len) {
			char **tmp = (char **) realloc (lista , (pos + 2) * sizeof (char *));
			if (tmp == NULL) { // No se pudo alocar la memoria
				free (lista);
				return NULL;
			}
			lista = tmp;
			tmp = NULL;

			lista[pos + 1] = NULL;
			lista[pos] = (char *) malloc (sizeof (char));
			if (lista[pos] == NULL) { // No se pudo alocar la memoria
				for (i = 0; i < pos; i++)
					free (lista[i]);
				free (lista);
				return NULL;
			}

			int j = 0;
			int k = -1;
			for (k = i; (p[k] != sep) && (k < len); k++) {
				lista[pos][j] = p[k];
				j++;
				char *tmp2 = (char *) realloc (lista[pos],(j + 1) * sizeof (char));
				if (lista[pos] == NULL) { // No se pudo alocar la memoria
					for (int h = 0; h < pos; h++){
						free (lista[h]);
					}
					free (lista);
					return NULL;
				}
				lista[pos] = tmp2;
				tmp2 = NULL;
			}
			i = k;
			lista[pos][j] = '\0';
			pos++;
		}
	}
	return lista;
}

int parserVectorDistancias(float** vectorDistancias, int cantGenesEnCromosoma){
	char str[50];
	float value1;
	float value2;
	FILE *fp = fopen("VectorCoordTCP.txt", "r");
	if(fp == NULL){
		return -1;
	}else{
		char **listSplit;
		short index;
		for(int i = 0; i < cantGenesEnCromosoma; i++){
			value1 = 0;
			value2 = 0;
			fscanf(fp, "%[^\n]", str);
			listSplit = NULL;
			listSplit = split(str,' ');
			if (listSplit != NULL){
				index = 0;
				atoi(listSplit[index]); //id no lo guardamos en el vector de distancias
				index++;
				value1 = atof(listSplit[index]);
				index++;
				value2 = atof(listSplit[index]);
				index++;
				getc(fp); //leer fin de linea
				vectorDistancias[i][0] = value1;
				vectorDistancias[i][1] = value2;
			}else{
				fclose(fp);
				return -2;
			}
		}
	}
	fclose(fp);
	return 0;
}

int cargarMatrizCostos (float* matrizCostosHost, float** vectorDistancias, int cantGenesEnCromosoma){
	float xa, ya, xb, yb;
	int fila = 0;
	int columna = 0;
	for (fila = 0; fila < cantGenesEnCromosoma; fila++){
		xa = vectorDistancias[fila][0];
		ya = vectorDistancias[fila][1];
		for (columna = 0; columna < fila; columna++){
			xb = vectorDistancias[columna][0];
			yb = vectorDistancias[columna][1]; 
			float distancia = sqrt(pow((xb - xa), 2) + pow((yb - ya), 2));
			//La matriz es simetrica
			matrizCostosHost[fila * cantGenesEnCromosoma + columna] = distancia;
			matrizCostosHost[columna * cantGenesEnCromosoma + fila] = distancia;
		}
		if (fila == columna){ //la diagonal se carga con 0's
			matrizCostosHost[fila * cantGenesEnCromosoma + columna] = 0;
		}
	}
	return 0;
}
#endif
